﻿using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using TMPro;

public class GameMgr : MonoSingleton<GameMgr>
{
    public PlayMode PlayMode;
    public string FileName;
    public TMP_Text gameTips;
    Dictionary<PlayMode, IPlayer> playerDict = new Dictionary<PlayMode, IPlayer>();
    IPlayer curPlayer;

    protected override void Init()
    {
        base.Init();
        playerDict.Add(PlayMode.Record, new Recorder());
        playerDict.Add(PlayMode.Replay, new Replayer());
        playerDict.Add(PlayMode.Rollback, new Rollback());

        var player = playerDict.GetValueOrDefault(PlayMode);
        string filePath = Path.Combine(Application.streamingAssetsPath, $"Data/{FileName}.json");
        player.Init(filePath);
        curPlayer = player;

        if (PlayMode == PlayMode.Record)
        {
            gameTips.text = "按下F1开始录制，按下F2停止录制";
        }
        else if (PlayMode == PlayMode.Replay)
        {
            gameTips.text = "按下F1开始播放，按下F2停止播放";
        }
        else if (PlayMode == PlayMode.Rollback)
        {
            gameTips.text = "按下F1开始回滚，按下F2停止回滚";
        }
    }

    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.F1))
        {
            curPlayer.Play();
        }
        else if (Input.GetKeyUp(KeyCode.F2))
        {
            curPlayer.Stop();
        }
    }

    private void FixedUpdate()
    {
        curPlayer.Update();
    }

    public void RecordPos(Unit unit, Vector3 pos, Vector3 dir)
    {
        if (PlayMode != PlayMode.Record)
            return;

        PosCmd cmd = new PosCmd()
        {
            Pos = pos.ToRVector3(),
            Dir = dir.ToRVector3(),
        };
        unit.DoCmd(CmdEnum.Pos, cmd);
    }

    public void RecordAllPos()
    {
        var dictUnit = UnitMgr.Instance.GetAllUnit();
        foreach (var item in dictUnit)
        {
            var unit = item.Value;
            var pos = unit.gameObject.transform.position;
            var dir = unit.gameObject.transform.eulerAngles;
            RecordPos(unit, pos, dir);
        }
    }

    public void ResetVelocity()
    {
        var dictUnit = UnitMgr.Instance.GetAllUnit();
        foreach (var item in dictUnit)
        {
            var unit = item.Value;
            MoveCmd cmd = new MoveCmd()
            {
                Velocity = Vector3.zero.ToRVector3(),
            };
            unit.DoCmd(CmdEnum.Move, cmd);
        }
    }

    public void Replay(Frame frame)
    {
        MonoHelper.Debug($"执行指令：{frame.Id} {frame.Cmd}");
        var unit = UnitMgr.Instance.GetUnit(frame.Owner);
        if (unit == null)
        {
            MonoHelper.Error($"未找到Owner {frame.Id} {frame.Cmd}");
            return;
        }

        CmdEnum type = (CmdEnum)frame.Cmd;
        ICommand cmd = null;
        if (type == CmdEnum.Pos)
        {
            cmd = JsonConvert.DeserializeObject<PosCmd>(frame.Data);
        }
        else if (type == CmdEnum.Move)
        {
            cmd = JsonConvert.DeserializeObject<MoveCmd>(frame.Data);
        }
        if (cmd == null)
        {
            MonoHelper.Error($"指令反序列化失败 {frame.Id} {frame.Cmd}");
            return;
        }
        unit.DoCmd(type, cmd);
    }

    public void Record(ICommand command, Unit unit)
    {
        if (PlayMode != PlayMode.Record)
            return;

        var recorder = curPlayer as Recorder;
        recorder.Record(command, unit.UnitId);
    }
}

public enum PlayMode
{
    Record,
    Replay,
    Rollback,
}

public interface IPlayer
{
    public void Init(string fileName);
    public void Play();
    public void Stop();
    public void Update();
}
